﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.ExpressionEvaluation
{
    /// <summary>
    /// This class represents a syntax notation checker for a stack based math notation. 
    /// Notationexample: 1 2 + 3 - sin.
    /// </summary>
    [Serializable]
    public class StackNotationSyntaxChecker
    {
        /// <summary>
        /// Includes the expression to check.
        /// </summary>
        private StackNotationParser parser;

        /// <summary>
        /// Initializes a new instance of the <see cref="StackNotationSyntaxChecker"/> class.
        /// </summary>
        /// <param name="parser">The parser which includes the expression to check.</param>
        public StackNotationSyntaxChecker(StackNotationParser parser)
        {
            if (parser == (StackNotationParser) null)
            {
                throw new ArgumentNullException("parser");
            }

            this.parser = parser;
        }

        /// <summary>
        /// Gets or sets the parser which includes the expression to check.
        /// </summary>
        /// <value>The parser which includes the expression to check.</value>
        public StackNotationParser Parser
        {
            get { return parser; }
            set { parser = value; }
        }

        /// <summary>
        /// Checks the syntax of the stack based expression.
        /// </summary>
        /// <returns>True if the syntax of the expression is correct otherwise, false.</returns>
        public bool CheckSyntax()
        {
            int numberOfOperators = 0;

            if ((!OperatorInformation.IsNumber(this.parser.CurrentToken())) ||
                (!OperatorInformation.IsNumber(this.parser.NextToken()) &&
                 (!OperatorInformation.IsOneParameterFunction(this.parser.NextToken()))))
            {
                return false;
            }

            while (this.parser.HasMoreTokens)
            {
                this.parser.ShiftRight();

                if (OperatorInformation.IsOperator(this.parser.CurrentToken()))
                {
                    if (!OperatorInformation.IsNumber(this.parser.PreviousToken()))
                    {
                        return false;
                    }

                    if (OperatorInformation.IsNumber(this.parser.PenultimateToken()) && !(this.parser.TokenIndex == 2))
                    {
                        return false;
                    }

                    numberOfOperators++;
                }
                else if (OperatorInformation.IsOneParameterFunction(this.parser.CurrentToken()))
                {
                    if (OperatorInformation.IsNumber(this.parser.PreviousToken()) && !(this.parser.TokenIndex == 1))
                    {
                        return false;
                    }

                    numberOfOperators++;
                }
                else if (OperatorInformation.IsTwoParameterFunction(this.parser.CurrentToken()))
                {
                    if (!OperatorInformation.IsNumber(this.parser.PreviousToken()))
                    {
                        return false;
                    }

                    if ((OperatorInformation.IsNumber(this.parser.PenultimateToken())) && !(this.parser.TokenIndex == 2))
                    {
                        return false;
                    }

                    numberOfOperators++;
                }
                else if (!OperatorInformation.IsNumber(this.parser.CurrentToken()))
                {
                    return false;
                }
            }

            return (numberOfOperators != 0) && (!OperatorInformation.IsNumber(this.parser.CurrentToken()));
        }
    }
}